<template>
    <div id="upload" :class="{show: showUploadTask, hide: !showUploadTask}">
        <div class="tasks">
            <div class="tasks-header">
                <h2 class="title">任务列表</h2>
            </div>
            <div class="tasks-body">
                <div class="tab-list">
                    <div class="tab-list-item">
                        任务({{uploadingFileList.length}})
                    </div>
                    <div class="tab-list-item" @click.stop="deleteAll">
                        删除未上传成功的文件
                    </div>
                    <div class="tab-list-item" @click.stop="deleteAllSuccessTask">
                        删除成功的任务
                    </div>
                </div>
                <div class="tab-list-group">
                    <div class="item-inner" v-for="(item, key) in uploadingFileList" :key="key">
                        <div class="thumb">
                            <Icon type="image" size="32" style="color:#f90" v-if="checkFileType(item.name) == '图片'"></Icon>
                            <Icon type="ios-musical-notes" size="32" style="rgb(53,132,225)" v-else-if="checkFileType(item.name) == '音乐'"></Icon>
                            <Icon type="social-youtube" size="32" style="color:#fe6428" v-else-if="checkFileType(item.name) == '视频'"></Icon>
                            <Icon type="document-text" size="32" style="rgb(106,138,177)" v-else-if="checkFileType(item.name) == '文档'"></Icon>
                            <Icon type="document" size="32" v-else-if="checkFileType(item.name) == '其他'"></Icon>
                        </div>
                        <div class="info">
                            <p class="title">
                                {{ item.name }}
                            </p>
                            <span class="size"> {{ getFilesize(item.contentSize) }}</span>
                            <span class="size">上传</span>
                        </div>
                        <p class="task-txt-status">{{item.status}}</p>
                        <div class="task-progress-status">
                            <i-circle :percent="item.percent" :size="36" :stroke-width="3">
                                <Icon v-if="item.percent == 100" type="ios-checkmark-empty" size="32" style="color:#5cb85c"></Icon>
                                <span style="font-size:10px" v-else>{{item.percent}}%</span>
                            </i-circle>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        <Upload-Drop @dropUpload="handleFileSelect"></Upload-Drop>
    </div>
</template>

<script>
import { ipcRenderer } from 'electron';
import axios from 'axios';

import Vue from 'vue';

// 引入加密 支持sha1 md5
import CryptoJS from './crypto.js';

export default {
    name: 'upload',
    components: {
        // 引入拖拽上传组件
        'Upload-Drop': require('./upload-drop.vue').default
    },
    props: {
        showUploadTask: {
            type: Boolean,
            default: false
        }
    },
    data() {
        return {
            file_id: 0,
            fileList: [],

            uploadingFileList: [],

            // 刷新列表延迟
            refreshTimer: null
        }
    },
    computed: {
        access_token() {
            return this.$store.getters.GET_ACCESSTOKEN;
        },
        folderid() {
            return this.$store.getters.GET_FOLDERID;
        },
    },
    mounted() {
        document.addEventListener('click', this.showTaskslistenEvent);
    },
    beforeDestroy(){
        document.removeEventListener('click', this.showTaskslistenEvent);
    },
    created() {
        // 监听上传任务回调
        ipcRenderer.on('uploadUrl-back', (event, data, pos) => {
            if (data.result.uploadResult["0"].uploadTaskID["0"] === "2swcGFp") {
                this.$Message.success('秒传成功！');
                if (this.refreshTimer) clearTimeout(this.refreshTimer);
                this.refreshTimer = setTimeout(() => {
                    this.$emit('refreshPath');
                }, 1500);
                return;
            }
            let obj = Object.assign({}, {
                file: this.uploadingFileList[pos].file,
                'Content-Type': this.uploadingFileList[pos]['Content-Type'],
                contentSize: this.uploadingFileList[pos].contentSize,
                name: this.uploadingFileList[pos].name,
                remainderOfSize: 0,
                posOnArr: pos,
                status: '上传中'
            }, {
                    redirectionUrl: data.result.uploadResult["0"].redirectionUrl["0"],
                    uploadTaskID: data.result.uploadResult["0"].uploadTaskID["0"].toString('base64'),
                });
            this.uploadingFileList[pos] = obj;
            this.uploadFile(this.uploadingFileList[pos]);
        });
    },
    methods: {
        // 点击其他位置自动关闭tasks
        closeTasks(bol) {
            this.$emit('toggleUploadTask', bol)
        },
        // 监听body上的点击事件，如果是点击到不是task上面则，关闭task显示
        showTaskslistenEvent(e){
            e.stopPropagation();
            if (!this.showUploadTask) return;
            let hasTarget = false;
            e.path.forEach((item) => {
                if (item.className == 'tasks') {
                    hasTarget = true;
                }
            });
            if (!hasTarget) this.closeTasks(false);
        },
        // 删除所有上传失败的文件
        deleteAll() {
            ipcRenderer.send('delete-allupload', {
                access_token: this.access_token,
                uploadTaskID: '0000',
                fileName: ''
            });
            ipcRenderer.once('deleteAllUpload-back', (event, data) => {
                if (data.result.$.resultCode === '0') {
                    this.$Message.success('删除成功！');
                }
            });
        },
        deleteAllSuccessTask() {
            for (let i = 0; i < this.uploadingFileList.length; i++) {
                if (this.uploadingFileList[i].status == '上传中') {
                    return;
                }
            }
            for (let i = 0; i < this.uploadingFileList.length; i++) {
                if (this.uploadingFileList[i].status == '上传成功') {
                    this.uploadingFileList.splice(i, 1);
                    i--;
                }
            }
        },
        upload(file) {
            let pos = this.uploadingFileList.push({});
            this.uploadingFileList[pos - 1] = {
                file: file,
                'Content-Type': `${file.type}; name=${encodeURIComponent(file.name)}`,
                contentSize: file.size,
                name: file.name,
                remainderOfSize: 0,
                posOnArr: pos - 1,
                status: '上传中'
            };
            ipcRenderer.send('get-uploadUrl', {
                access_token: this.access_token,
                folderid: this.folderid,
                filename: file.name,
                filesize: file.size,
                file_md5: file.hash[0].hash,
                pos: pos - 1
            });
        },
        uploadFile(obj) {
            let left = obj.remainderOfSize;
            let _this = this;
            let _vue = Vue;
            axios.post(obj.redirectionUrl, obj.file.slice(left == 0 ? 0 : left - 1, obj.contentSize), {
                headers: {
                    'Content-Type': obj['Content-Type'],
                    uploadTaskID: obj.uploadTaskID,
                    Range: `bytes=${left == 0 ? 0 : left - 1}-${obj.contentSize}`,
                    contentSize: obj.contentSize,
                    rangeType: 1
                },
                withCredentials: true,
                timeout: 1000 * 3600,
                onUploadProgress(handle) {
                    obj.loaded = handle.loaded;
                    obj.percent = Math.floor(((obj.remainderOfSize + obj.loaded) * 100 / obj.contentSize));
                    _vue.set(_this.uploadingFileList, obj.posOnArr, obj);
                }
            }).then((res) => {
                console.log(res);
                if (res.data.indexOf('0') != -1) {
                    obj.remainderOfSize = obj.remainderOfSize + obj.loaded;
                    obj.loaded = 0;
                    if (obj.remainderOfSize >= obj.contentSize) {
                        this.completeUpload(obj);
                    } else {
                        this.uploadFile(obj);
                    }
                    return;
                }
            }).catch((err) => {
                if (err.toString().indexOf('Error: Network Error') != -1) {
                    if (obj.remainderOfSize + obj.loaded < obj.contentSize && obj.loaded != 0) {
                        if (obj.contentSize > 1024 * 1024 * 3) {
                            obj.remainderOfSize = obj.remainderOfSize + obj.loaded - 1024 * 1024 * 3;
                            obj.loaded = 0;
                            this.uploadFile(obj);
                        } else {
                            obj.remainderOfSize = 0;
                            obj.loaded = 0;
                            this.uploadFile(obj);
                        }
                    } else if (obj.remainderOfSize + obj.loaded < obj.contentSize && obj.loaded == 0) {
                        this.uploadFile(obj);
                        return;
                    } else if (obj.remainderOfSize + obj.loaded == obj.contentSize) {
                        obj.remainderOfSize = obj.remainderOfSize + obj.loaded;
                        this.completeUpload(obj);
                        return;
                    }
                } else if (err.response) {
                    console.log(err.response);
                    if (err.response.data.indexOf('9131') != -1) {
                        this.$Message.error('发生错误！错误代码 9131');
                    }
                }
            })
        },
        completeUpload(obj) {
            let left = obj.remainderOfSize;
            axios.post(obj.redirectionUrl, obj.file.slice(left, obj.contentSize), {
                headers: {
                    'Content-Type': obj['Content-Type'],
                    uploadTaskID: obj.uploadTaskID,
                    Range: `bytes=${left}-${obj.contentSize}`,
                    contentSize: obj.contentSize,
                    rangeType: 2,
                },
                withCredentials: true,
                timeout: 1000 * 3600
            }).then((res) => {
                this.$Message.success('上传成功！');
                obj.status = '上传成功';
                if (this.refreshTimer) clearTimeout(this.refreshTimer);
                this.refreshTimer = setTimeout(() => {
                    this.$emit('refreshPath');
                }, 1500);
                console.log(res);
            }).catch((err) => {
                console.log(err);
                if (err.response) {
                    if (err.response.data.indexOf('9131') != -1) {
                        this.$Message.error('发生错误！错误代码 9131');
                    } else if (err.response.data.indexOf('9136') != -1) {
                        this.$Message.error('发生错误！错误代码 9136');
                    }
                }
            })
        },
        // 计算出文件md5 然后上传
        handleFileSelect(files) {
            for (let i = 0, f; f = files[i]; i++) {
                // 计算文件hash的算法类型 可以加入md5 sha1 sha256等等
                let algorithms = [
                    { name: "MD5", type: CryptoJS.algo.MD5 }
                ];
                let enabledAlgorithms = [];
                for (let j = 0; j < algorithms.length; j++) {
                    let current = algorithms[j];
                    enabledAlgorithms.push({ name: current.name, instance: current.type.create(current.param) });
                }
                this.file_id++;
                let uid = "filehash" + this.file_id;

                this.fileList.push({
                    uid: uid,
                    file: files[i],
                    progress: 0,
                    isupload: true
                });

                this.progressiveRead(f, (data, pos, file) => {
                    // 开始操作
                    if (enabledAlgorithms.length > 0) {
                        var wordArray = this.arrayBufferToWordArray(data);
                    }

                    for (let j = 0; j < enabledAlgorithms.length; j++) {
                        enabledAlgorithms[j].instance.update(wordArray);
                    }
                    // 更新进度条显示
                    let progress = Math.floor((pos / file.size) * 100);
                    for (let item in this.fileList) {
                        if (this.fileList[item].uid === uid) {
                            this.fileList[item].progress = progress;
                        }
                    }
                }, (file) => {
                    // 文件hash计算完成后进行的操作
                    // console.log(file)
                    for (let j = 0; j < enabledAlgorithms.length; j++) {
                        file.hash = [];
                        file.hash.push({
                            hashname: enabledAlgorithms[j].name,
                            hash: enabledAlgorithms[j].instance.finalize().toString()
                        });
                    }
                    // console.log(file);
                    this.upload(file);
                    // console.log({
                    //     hash: file.hash[0].hash,
                    //     filename: file.name,
                    //     filesize: file.size
                    // });
                });
            }
        },
        // 分片计算md5
        progressiveRead(file, work, done) {
            let chunkSize = 2048000; // 200KiB at a time
            let pos = 0;
            let reader = new FileReader();
            let blob;

            function progressiveReadNext() {
                let end = Math.min(pos + chunkSize, file.size);

                reader.onload = function (e) {
                    pos = end;
                    work(e.target.result, pos, file);
                    if (pos < file.size) {
                        setTimeout(progressiveReadNext, 0);
                    }
                    else {
                        // Done
                        done(file);
                    }
                };
                if (file.slice) {
                    blob = file.slice(pos, end);
                    reader.readAsArrayBuffer(blob);
                } else if (file.webkitSlice) {
                    blob = file.webkitSlice(pos, end);
                    reader.readAsArrayBuffer(blob);
                }
            }
            setTimeout(progressiveReadNext, 0);
        },
        arrayBufferToWordArray(arrayBuffer) {
            let fullWords = Math.floor(arrayBuffer.byteLength / 4);
            let bytesLeft = arrayBuffer.byteLength % 4;

            let u32 = new Uint32Array(arrayBuffer, 0, fullWords);
            let u8 = new Uint8Array(arrayBuffer);

            let cp = [];
            for (let i = 0; i < fullWords; ++i) {
                cp.push(this.swapendian32(u32[i]));
            }

            if (bytesLeft) {
                let pad = 0;
                for (let i = bytesLeft; i > 0; --i) {
                    pad = pad << 8;
                    pad += u8[u8.byteLength - i];
                }

                for (let i = 0; i < 4 - bytesLeft; ++i) {
                    pad = pad << 8;
                }

                cp.push(pad);
            }
            return CryptoJS.lib.WordArray.create(cp, arrayBuffer.byteLength);
        },
        swapendian32(val) {
            return (((val & 0xFF) << 24)
                | ((val & 0xFF00) << 8)
                | ((val >> 8) & 0xFF00)
                | ((val >> 24) & 0xFF)) >>> 0;
        },
        // 转换文件大小
        getFilesize(filesize) {
            if (!filesize) return '/';
            let tempsize = Number(filesize);
            if (!Number.isInteger(tempsize)) return '/';
            let unitArr = new Array("Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB");
            let index = 0;
            let srcsize = parseFloat(tempsize);
            index = Math.floor(Math.log(srcsize) / Math.log(1024));
            let size = srcsize / Math.pow(1024, index);
            size = size.toFixed(2);//保留的小数位数
            return size + unitArr[index];
        },
        // 根据后缀查类型
        checkFileType: function (filename) {
            let suffix = filename.substring(filename.lastIndexOf('.') + 1).toLowerCase();
            let type = "";
            switch (suffix) {
                case 'mp4':
                case 'mpeg':
                case 'avi':
                case 'mov':
                case 'wmv':
                case '3gp':
                case 'mkv':
                case 'flv':
                case 'f4v':
                case 'rmvb':
                case 'webm':
                case 'qsv':
                    type = '视频';
                    break;
                case 'mp3':
                case 'wma':
                case 'wav':
                case 'aac':
                case 'asf':
                case 'flac':
                case 'ape':
                case 'mid':
                case 'ogg':
                case 'm4a':
                    type = '音乐';
                    break;
                case 'ppt':
                case 'pptx':
                case 'doc':
                case 'docx':
                case 'pdf':
                case 'txt':
                case 'xls':
                case 'wps':
                    type = '文档';
                    break;
                case 'jpg':
                case 'jpeg':
                case 'png':
                case 'bmp':
                case 'gif':
                case 'psd':
                case 'tiff':
                case 'svg':
                    type = '图片';
                    break;
                case 'rar':
                case 'zip':
                case '7z':
                case 'tgz':
                case 'iso':
                    type = '压缩文件';
                    break;
                default:
                    type = '其他';
            }
            return type;
        }
    }
}
</script>


<style>
#upload .tasks {
  visibility: hidden;
  pointer-events: none;
  opacity: 0;
  transform-origin: right top;
  /* display: none; */
  position: absolute;
  top: 44px;
  right: 22px;
  z-index: 4;
  width: 540px;
  height: 377px;
  overflow: hidden;
  box-sizing: border-box;
  border-radius: 4px;
  border: 1px solid rgba(0, 0, 0, 0.21);
  border-top: none;
  background-color: #fff;
  box-shadow: 0 1px 4px 0 rgba(15, 32, 66, 0.2);
}
#upload .tasks::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 4px;
  border-top-left-radius: 4px;
  border-top-right-radius: 4px;
  background-color: #00a4ff;
  z-index: 4;
}
#upload.hide .tasks {
  opacity: 0;
  visibility: hidden;
  animation: HideTask 0.3s 0s forwards;
  pointer-events: none;
}
@keyframes HideTask {
  0% {
    opacity: 1;
    visibility: visible;
    transform: scale(1);
  }
  100% {
    opacity: 0;
    transform: scale(0);
  }
}
#upload.show .tasks {
  visibility: visible;
  pointer-events: auto;
  opacity: 1;
  animation: showTask 0.3s 0s forwards;
}
@keyframes showTask {
  0% {
    opacity: 0;
    transform: scale(0);
  }
  70% {
    opacity: 1;
    transform: scale(1.04);
  }
  100% {
    transform: scale(1);
  }
}
#upload .tasks .tasks-header {
  position: relative;
}
#upload .tasks .tasks-header {
  height: auto;
  padding: 16px 20px 15px 31px;
  height: 56px;
  box-sizing: border-box;
  overflow: hidden;
  line-height: 1.85;
}
#upload .tasks .tasks-header .title {
  font-size: 18px;
  font-family: -apple-system, BlinkSystemFont, "Segoe UI", Roboto, Ubuntu,
    "Helvetica Neue", Helevetica, Arial, "PingFang SC", "Hiragino Sans GB",
    "Microsoft YaHei UI", "Microsoft YaHei", "Source Han Sans CN", sans-serif;
}

#upload .tasks .tasks-body {
  white-space: nowrap;
  font-size: 0;
  transition: transform 0.2s linear;
}

#upload .tasks .tab-list {
  display: flex;
  flex-direction: row;
  height: 47px;
  line-height: 47px;
  box-sizing: border-box;
  padding-left: 31px;
  padding-right: 20px;
  border-bottom: 1px solid #e8eaeb;
  font-size: 14px;
}
#upload .tasks .tab-list .tab-list-item {
  height: auto;
  line-height: 47px;
  margin-right: 22px;
  cursor: pointer;
}
#upload .tasks .tab-list .tab-list-item:last-child {
  margin-right: 0;
}
#upload .tasks .tab-list-group {
  width: 100%;
  height: 272px;
  overflow: auto;
  overflow-x: hidden;
  white-space: nowrap;
}
#upload .tasks .tab-list-group .item-inner {
  position: relative;
  padding: 14px 20px;
  line-height: 1.1;
  font-size: 0;
  display: flex;
  flex-direction: row;
}
#upload .tasks .tab-list-group .item-inner .thumb {
  display: inline-block;
  vertical-align: middle;
  width: 40px;
  height: 40px;
  margin-left: 11px;
}
#upload .tasks .tab-list-group .item-inner .info {
  flex: 1;
  margin-right: 40px;
  display: inline-block;
  vertical-align: middle;
  font-size: 14px;
}
#upload .tasks .tab-list-group .item-inner .info .title {
  max-width: 280px;
  height: 22px;
  line-height: 1.3;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
#upload .tasks .tab-list-group .item-inner .info .size {
  font-size: 12px;
  margin-right: 4px;
  color: #777;
}
#upload .tasks .tab-list-group .item-inner .task-txt-status {
  margin-right: 27px;
  font-size: 14px;
  line-height: 40px;
}
#upload .tasks .tab-list-group .item-inner .task-progress-status {
  position: relative;
  width: 36px;
  height: 36px;
}
</style>